﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Itfort;
using MySoft.Data;

namespace Users
{
	/// <summary>
	/// 用户服务实现。
	/// </summary>
	public class UserService : IUserService
	{
		private DbSession dbSession = new DbSession("Users");

		/// <summary>
		/// 创建用户。
		/// </summary>
		/// <param name="username">用户名。</param>
		/// <param name="password">密码。</param>
		/// <param name="email">电子邮箱。</param>
		/// <returns>新创建的用户对应的User对象。</returns>
		/// <exception cref="UCExceiption"></exception>
		public User CreateUser(string username, string password)
		{
			this.CreateUser(username, password, null, null, 0, 0, null);
			return this.GetUser(username);
		}

		/// <summary>
		/// 创建用户。
		/// </summary>
		/// <param name="email">电子邮箱。</param>
		/// <param name="password">密码。</param>
		/// <param name="nickname">昵称</param>
		/// <returns>新创建的用户对应的User对象。</returns>
		public User CreateUserByEmail(string email, string password, string nickname)
		{
			this.CreateUser(null, password, email, null, 0, 0, nickname);
			return this.GetUserByEmail(email);
		}

		/// <summary>
		/// 创建用户。
		/// </summary>
		/// <param name="mobile">手机号码。</param>
		/// <param name="password">密码。</param>
		/// <param name="nickname">昵称</param>
		/// <returns>新创建的用户对应的User对象。</returns>
		public User CreateUserByMobile(string mobile, string password, string nickname)
		{
			this.CreateUser(null, password, null, mobile, 0, 0, nickname);
			return this.GetUserByMobile(mobile);
		}

		/// <summary>
		/// 创建用户。
		/// </summary>
		/// <param name="username">用户名。</param>
		/// <param name="password">密码。</param>
		/// <param name="email">电子邮箱。</param>
		/// <param name="mobile">手机号码。</param>
		/// <param name="emailStatus">邮箱状态。</param>
		/// <param name="mobileStatus">手机状态。</param>
		/// <param name="nickname">昵称。</param>
		/// <returns></returns>
		internal void CreateUser(string username, string password, string email, string mobile, int emailStatus, int mobileStatus, string nickname)
		{
			_User _user = new _User();
			_user.Username = username;
			_user.Password = password;
			_user.PasswordSalt = null;
			_user.Email = email;
			_user.Mobile = mobile;
			_user.EmailStatus = emailStatus;
			_user.MobileStatus = mobileStatus;
			_user.Nickname = nickname;
			_user.CreationTime = DateTime.Now;

			dbSession.Save(_user);
		}

		/// <summary>
		/// 创建用户。
		/// </summary>
		/// <param name="dbTrans">事务对象。</param>
		/// <param name="username">用户名。</param>
		/// <param name="password">密码。</param>
		/// <param name="email">电子邮箱。</param>
		/// <param name="mobile">手机号码。</param>
		/// <param name="emailStatus">邮箱状态。</param>
		/// <param name="mobileStatus">手机状态。</param>
		/// <param name="nickname">昵称。</param>
		/// <returns></returns>
		internal User CreateUser(DbTrans dbTrans, string username, string password, string email, string mobile, int emailStatus, int mobileStatus, string nickname)
		{
			_User _user = new _User();
			_user.Username = username;
			_user.Password = password;
			_user.PasswordSalt = null;
			_user.Email = email;
			_user.Mobile = mobile;
			_user.EmailStatus = emailStatus;
			_user.MobileStatus = mobileStatus;
			_user.Nickname = nickname;
			_user.CreationTime = DateTime.Now;

			dbTrans.Save(_user);
			return dbTrans.Single<_User>(_User._.Id == _user.Id).Convert2<User>();
		}

		/// <summary>
		/// 获取用户。
		/// </summary>
		/// <param name="id">用户编号。</param>
		/// <returns>一个User对象，它表示指定的用户。</returns>
		public User GetUser(int id)
		{
			return dbSession.Single<_User>(_User._.Id == id).Convert2<User>();
		}

		/// <summary>
		/// 获取用户。
		/// </summary>
		/// <param name="username">用户名。</param>
		/// <returns>一个User对象，它表示指定的用户。</returns>
		public User GetUser(string username)
		{
			Utility.ThrowNullOrEmpty(username, "参数username不能为空");
			return dbSession.Single<_User>(_User._.Username == username).Convert2<User>();
		}

		/// <summary>
		/// 获取用户。
		/// </summary>
		/// <param name="email">电子邮箱。</param>
		/// <returns>一个User对象，它表示指定的用户。</returns>
		public User GetUserByEmail(string email)
		{
			Utility.ThrowNullOrEmpty(email, "参数email不能为空");
			return dbSession.Single<_User>(_User._.Email == email).Convert2<User>();
		}

		/// <summary>
		/// 获取用户。
		/// </summary>
		/// <param name="mobile">手机号码。</param>
		/// <returns>一个User对象，它表示指定的用户。</returns>
		public User GetUserByMobile(string mobile)
		{
			Utility.ThrowNullOrEmpty(mobile, "参数mobile不能为空");
			return dbSession.Single<_User>(_User._.Mobile == mobile).Convert2<User>();
		}

		/// <summary>
		/// 获取用户集合。
		/// </summary>
		/// <param name="pageIndex">页索引。</param>
		/// <param name="pageSize">页大小。</param>
		/// <returns>User对象集合。</returns>
		public IList<User> GetUsers(Int32 pageIndex, Int32 pageSize)
		{
			return dbSession.From<_User>().OrderBy(_User._.CreationTime.Desc)
				.GetPage(pageSize)
				.ToList(pageIndex)
				.Convert2<User>();
		}

		/// <summary>
		/// 获取用户数量。
		/// </summary>
		/// <returns>用户数量。</returns>
		public Int32 GetCount()
		{
			return dbSession.Count<_User>(WhereClip.None);
		}

		/// <summary>
		/// 获取用户集合，匹配用户名。
		/// </summary>
		/// <param name="username">要匹配的用户名。</param>
		/// <param name="pageIndex">页索引。</param>
		/// <param name="pageSize">页大小。</param>
		/// <returns>User对象集合。</returns>
		public IList<User> FindUsers(string username, Int32 pageIndex, Int32 pageSize)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// 获取用户集合，匹配电子邮箱。
		/// </summary>
		/// <param name="email">电子邮箱。</param>
		/// <param name="username">要匹配的用户名。</param>
		/// <param name="pageIndex">页索引。</param>
		/// <param name="pageSize">页大小。</param>
		/// <returns>User对象集合。</returns>
		public IList<User> FindUsersByEmail(string email, Int32 pageIndex, Int32 pageSize)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// 获取用户集合，匹配手机号码。
		/// </summary>
		/// <param name="mobile">手机号码。</param>
		/// <param name="username">要匹配的用户名。</param>
		/// <param name="pageIndex">页索引。</param>
		/// <param name="pageSize">页大小。</param>
		/// <returns>User对象集合。</returns>
		public IList<User> FindUsersByMobile(string mobile, Int32 pageIndex, Int32 pageSize)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// 验证密码
		/// </summary>
		/// <param name="password">明文密码</param>
		/// <param name="salt">错位码</param>
		/// <param name="encryptedPassword">加密后密码</param>
		/// <returns></returns>
		public bool ValidatePassword(string password, string salt, string encryptedPassword)
		{
			string inEncryptedPassword = this.EncryptPassword(password, salt);
			return inEncryptedPassword == encryptedPassword;
		}

		/// <summary>
		/// 验证密码是否正确
		/// </summary>
		/// <param name="id">用户编号</param>
		/// <param name="password">密码</param>
		/// <returns></returns>
		public bool ValidateUser(int id, string password)
		{
			Utility.ThrowNullOrEmpty(password, "参数password不能为空");

			User user = this.GetUser(id);
			// 用户名不存在
			if (user == null) return false;
			return this.ValidatePassword(password, user.PasswordSalt, user.Password);
		}

		/// <summary>
		/// 验证用户名和密码是否有效。
		/// </summary>
		/// <param name="username">用户名。</param>
		/// <param name="password">密码。</param>
		/// <returns>如果有效，返回true；否则返回false。</returns>
		public Boolean ValidateUser(string username, string password)
		{
			Utility.ThrowNullOrEmpty(username, "参数username不能为空");
			Utility.ThrowNullOrEmpty(password, "参数password不能为空");

			User user = this.GetUser(username);
			// 对应用户名的用户不存在
			if (user == null) return false;
			return this.ValidatePassword(password, user.PasswordSalt, user.Password);
		}

		/// <summary>
		/// 验证电子邮箱和密码是否有效。
		/// </summary>
		/// <param name="email">电子邮箱</param>
		/// <param name="password">密码。</param>
		/// <returns>如果有效，返回true；否则返回false。</returns>
		/// <exception cref="UCExceiption">未开启电子邮箱登陆。</exception>
		public Boolean ValidateUserByEmail(string email, string password)
		{
			Utility.ThrowNullOrEmpty(email, "参数username不能为空");
			Utility.ThrowNullOrEmpty(password, "参数password不能为空");

			User user = this.GetUserByEmail(email);
			// 对应电子邮箱的用户不存在
			if (user == null) return false;
			return this.ValidatePassword(password, user.PasswordSalt, user.Password);
		}

		/// <summary>
		/// 验证手机号码和密码是否有效。
		/// </summary>
		/// <param name="mobile">手机号码。</param>
		/// <param name="password">密码。</param>
		/// <returns>如果有效，返回true；否则返回false。</returns>
		/// <exception cref="UCExceiption">为开启手机号码登陆。</exception>
		public Boolean ValidateuserByMobile(string mobile, string password)
		{
			Utility.ThrowNullOrEmpty(mobile, "参数username不能为空");
			Utility.ThrowNullOrEmpty(password, "参数password不能为空");

			User user = this.GetUserByEmail(mobile);
			// 对应手机号码的用户不存在
			if (user == null) return false;
			return this.ValidatePassword(password, user.PasswordSalt, user.Password);
		}

		/// <summary>
		/// 核对用户名有效性。
		/// </summary>
		/// <param name="username">被核对的用户名。</param>
		/// <param name="errorCode">
		/// 当此方法返回时，如果结果为false，则设置对应的错误代码；否则返回null。
		/// 可能的值为ErrorCodes.InvalidUserName或ErrorCodes.UserNameAlreadyExists。
		/// </param>
		/// <returns>
		/// 如果用户名合法，则返回true；否则返回false。
		/// </returns>
		public Boolean CheckUsername(string username, out ErrorCode errorCode)
		{
			// 检查用户名字符组合有效性
			if (Utility.ValidateUsernameFormat(username))
			{// 有效
				// 检查用户名是否已存在
				if (!this.ExistsUsername(username))
				{// 不存在
					errorCode = null;
					return true;
				}
				else
				{// 已存在
					errorCode = ErrorCodes.UserNameAlreadyExists;
					return false;
				}
			}
			else
			{// 无效
				errorCode = ErrorCodes.InvalidUsername;
				return false;
			}
		}

		/// <summary>
		/// 核对昵称合法性。
		/// </summary>
		/// <param name="nickname">被核对的昵称。</param>
		/// <param name="errorCode">
		/// 当此方法返回时，如果结果为false，则设置对应的错误代码；否则返回null。
		/// </param>
		/// <returns>如果用户名合法，则返回true；否则返回false。</returns>
		public bool CheckNickname(string nickname, out ErrorCode errorCode)
		{
			// 检查昵称字符组合有效性
			if (Utility.ValidateUsernameFormat(nickname))
			{// 有效
				// 检查用户名是否已存在
				if (!this.ExistsNickname(nickname))
				{// 合法
					errorCode = null;
					return true;
				}
				else
				{// 已存在
					errorCode = ErrorCodes.NicknameAlreadyExists;
					return false;
				}
			}
			else
			{// 无效
				errorCode = ErrorCodes.InvalidNickname;
				return false;
			}
		}

		/// <summary>
		/// 核对昵称合法性。
		/// </summary>
		/// <param name="nickname">被核对的昵称。</param>
		/// <param name="exceptUserId">排除某个用户</param>
		/// <param name="errorCode">
		/// 当此方法返回时，如果结果为false，则设置对应的错误代码；否则返回null。
		/// </param>
		/// <returns>如果用户名合法，则返回true；否则返回false。</returns>
		public bool CheckNickname(string nickname, int exceptUserId, out ErrorCode errorCode)
		{
			// 检查昵称字符组合有效性
			if (Utility.ValidateUsernameFormat(nickname))
			{// 有效
				// 检查用户名是否已存在
				if (!this.ExistsNickname(nickname, exceptUserId))
				{// 合法
					errorCode = null;
					return true;
				}
				else
				{// 已存在
					errorCode = ErrorCodes.NicknameAlreadyExists;
					return false;
				}
			}
			else
			{// 无效
				errorCode = ErrorCodes.InvalidNickname;
				return false;
			}
		}

		/// <summary>
		/// 核对电子邮箱有效性。
		/// </summary>
		/// <param name="email">被核对的电子邮箱。</param>
		/// <param name="errorCode">
		/// 当此方法返回时，如果结果为false，则设置对应的错误代码；否则返回null。
		/// 可能的值为ErrorCodes.InvalidEmail或ErrorCodes.EmailAlreadyExists。
		/// </param>
		/// <returns>
		/// 如何电子邮箱合法，则返回true；否则返回false。
		/// </returns>
		public Boolean CheckEmail(string email, out ErrorCode errorCode)
		{
			// 检查电子邮件字符组合有效性
			if (Utility.ValidateEmailFormat(email))
			{// 有效
				// 检查电子邮箱是否已存在
				if (!this.ExistsEmail(email))
				{// 不存在
					errorCode = null;
					return true;
				}
				else
				{// 已存在
					errorCode = ErrorCodes.EmailAlreadyExists;
					return false;
				}
			}
			else
			{// 无效
				errorCode = ErrorCodes.InvalidEmail;
				return false;
			}
		}

		/// <summary>
		/// 核对电子邮箱有效性
		/// </summary>
		/// <param name="email">被核对的电子邮箱</param>
		/// <param name="exceptUserId">排除某个用户</param>
		/// <param name="errorCode">
		/// 当此方法返回时，如果结果为false，则设置对应的错误代码；否则返回null。
		/// 可能的值为ErrorCodes.InvalidEmail或ErrorCodes.EmailAlreadyExists。
		/// </param>
		/// <returns>
		/// 如何电子邮箱合法，则返回true；否则返回false。
		/// </returns>
		public bool CheckEmail(string email, int exceptUserId, out ErrorCode errorCode)
		{
			// 检查电子邮件字符组合有效性
			if (MyValidator.Email(email))
			{// 有效
				// 检查电子邮箱是否已存在
				if (!this.ExistsEmail(email, exceptUserId))
				{// 不存在
					errorCode = null;
					return true;
				}
				else
				{// 已存在
					errorCode = ErrorCodes.EmailAlreadyExists;
					return false;
				}
			}
			else
			{// 无效
				errorCode = ErrorCodes.InvalidEmail;
				return false;
			}
		}

		/// <summary>
		/// 核对手机号码有效性。
		/// </summary>
		/// <param name="mobile">被核对的手机号码。</param>
		/// <param name="errorCode">
		/// 当此方法返回时，如果结果为false，则设置对应的错误代码；否则返回null。
		/// </param>
		/// <returns>
		/// 如何电子手机号码，则返回true；否则返回false。
		/// </returns>
		public Boolean CheckMobile(string mobile, out ErrorCode errorCode)
		{
			// 检查手机号码字符组合有效性
			if (Regex.IsMatch(mobile, ""))
			{// 有效
				// 检查手机号码是否已存在
				if (!this.ExistsMobile(mobile))
				{// 不存在
					errorCode = null;
					return true;
				}
				else
				{// 已存在
					errorCode = ErrorCodes.MobileAlreadyExists;
					return false;
				}
			}
			else
			{// 无效
				errorCode = ErrorCodes.InvalidMobile;
				return false;
			}
		}

		/// <summary>
		/// 用户名是否存在。
		/// </summary>
		/// <param name="username">要检查的用户名。</param>
		/// <returns>如果存在，则返回true；否则返回false。</returns>
		public Boolean ExistsUsername(string username)
		{
			Utility.ThrowNullOrEmpty(username, "参数username不能为空");
			return dbSession.Exists<_User>(_User._.Username == username);
		}

		/// <summary>
		/// 昵称是否存在。
		/// </summary>
		/// <param name="nickname">要检查的昵称。</param>
		/// <returns>如果存在，则返回true；否则返回false。</returns>
		public Boolean ExistsNickname(string nickname)
		{
			Utility.ThrowNullOrEmpty(nickname, "参数nickname不能为空");
			return dbSession.Exists<_User>(_User._.Nickname == nickname);
		}

		/// <summary>
		/// 昵称是否存在。
		/// </summary>
		/// <param name="nickname">要检查的昵称。</param>
		/// <param name="exceptUserId">排除某个用户</param>
		/// <returns>如果存在，则返回true；否则返回false。</returns>
		public Boolean ExistsNickname(string nickname, int exceptUserId)
		{
			Utility.ThrowNullOrEmpty(nickname, "参数nickname不能为空");
			return dbSession.Exists<_User>(_User._.Nickname == nickname && _User._.Id != exceptUserId);
		}

		/// <summary>
		/// 电子邮箱是否存在。
		/// </summary>
		/// <param name="email">要检查的电子邮箱。</param>
		/// <returns>如果存在，则返回true；否则返回false。</returns>
		public bool ExistsEmail(string email)
		{
			Utility.ThrowNullOrEmpty(email, "参数email不能为空");
			return dbSession.Exists<_User>(_User._.Email == email);
		}

		/// <summary>
		/// 电子邮箱是否存在
		/// </summary>
		/// <param name="email">要检查的电子邮箱</param>
		/// <param name="exceptUserId">排除某个用户</param>
		/// <returns>如果存在，则返回true；否则返回false。</returns>
		public bool ExistsEmail(string email, int exceptUserId)
		{
			Utility.ThrowNullOrEmpty(email, "参数email不能为空");
			return dbSession.Exists<_User>(_User._.Email == email && _User._.Id != exceptUserId);
		}

		/// <summary>
		/// 手机号码是否存在。
		/// </summary>
		/// <param name="username">要检查的手机号码。</param>
		/// <returns>如果存在，则返回true；否则返回false。</returns>
		public Boolean ExistsMobile(string mobile)
		{
			Utility.ThrowNullOrEmpty(mobile, "参数mobile不能为空"); if (String.IsNullOrEmpty(mobile))
			{
				throw new UCException();
			}
			return dbSession.Exists<_User>(_User._.Mobile == mobile);
		}

		/// <summary>
		/// 修改用户头像。
		/// </summary>
		/// <param name="id">用户编号。</param>
		/// <param name="avatar">用户头像。</param>
		public void UpdateAvatar(int id, string avatar)
		{
			dbSession.Update<_User>(_User._.Avatar, avatar, _User._.Id == id);
		}

		/// <summary>
		/// 更新电子邮箱，邮箱状态为未验证（0）
		/// </summary>
		/// <param name="id">用户编号</param>
		/// <param name="email">电子邮箱</param>
		public void UpdateEmail(int id, string email)
		{
			this.UpdateEmail(id, email, 0);
		}

		/// <summary>
		/// 更新电子邮箱和邮箱状态
		/// </summary>
		/// <param name="id">用户编号</param>
		/// <param name="email">电子邮箱</param>
		/// <param name="emailStatus">邮箱状态（0-未验证；1-已验证）</param>
		public void UpdateEmail(int id, string email, int emailStatus)
		{
			dbSession.Update<_User>(
				new Field[] { _User._.Email, _User._.EmailStatus },
				new object[] { email, emailStatus },
				_User._.Id == id);
		}

		/// <summary>
		/// 更新密码
		/// </summary>
		/// <param name="id">用户编号</param>
		/// <param name="password">密码</param>
		public void UpdatePassword(int id, string password)
		{
			var salt = this.NewPasswordSalt();
			var encryptedPassword = this.EncryptPassword(password, salt);

			dbSession.Update<_User>(
				new Field[] { _User._.Password, _User._.PasswordSalt },
				new object[] { encryptedPassword, salt },
				_User._.Id == id);
		}

		/// <summary>
		/// 修改昵称
		/// </summary>
		/// <param name="id">用户编号</param>
		/// <param name="nickname">昵称</param>
		public void UpdateNickname(int id, string nickname)
		{
			dbSession.Update<_User>(
				new Field[] { _User._.Nickname },
				new object[] { nickname },
				_User._.Id == id);
		}

		/// <summary>
		/// 初始化一个密码Salt
		/// </summary>
		/// <returns></returns>
		private string NewPasswordSalt()
		{
			return Guid.NewGuid().ToString().Substring(0, 6);
		}

		/// <summary>
		/// 加密密码
		/// </summary>
		/// <param name="password">明文密码</param>
		/// <param name="salt">错位码</param>
		/// <returns></returns>
		private string EncryptPassword(string password, string salt)
		{
			string value = salt + password;
			return MyEncrypt.GetMD5Hash(value);
		}
	}
}
